from socket import socket
import socket as Socket
from threading import Thread
from queue import Queue
from Logger import logger
import os,sys,re
from enum import Enum
from stopThread import stop_thread

def and_split(body):
    out = ""
    b = body.split("&")
    for i in b:
        k = i.split("=")
        if len(k[1])==0:
            out += " SYSTEM_FLAG_EMPTY"
        else:
            out += " " + k[1]
    return out


class MIME(Enum):
    plain = "text/plain"
    html = "text/html"
    png = "image/png"
    icon = "image/x-icon"


class request:
    _r = re.compile(
        r"(GET|HEAD|POST|\w{3,4}) /(\S*) HTTP/(\S+)\r\n((?:[^\r]+\r\n)*)\r\n(\S*)"
    )

    def __init__(self, request: bytes):
        parameter = re.match(self._r, request.decode())
        if parameter:
            self.method: str = parameter[1]
            self.target: str = parameter[2]
            self.version: str = parameter[3]
            headers_str: str = parameter[4]
            r = re.compile(r"(\S+)\s*:\s*([^\r]+)\r\n")
            self.headers = dict(r.findall(headers_str))
            self.body: str = parameter[5]
        else:
            raise Exception


def response(code: int, type: MIME, content: bytes, head=False) -> bytes:
    res = f"HTTP/1.0 {code}\nContent-type:{type.value}\nContent-Length:{len(content)}\nConnection: Keep-Alive\n\n"
    if not head:
        return res.encode() + content
    else:
        return res.encode()



def echo_client(q,):
    def send_file(req: request, file, type: MIME):
        u = 404 if file == '404.html' else 200
        with open(file, "rb") as f:
            b = f.read(1048576)
            sock.send(response(u, type, b, req.method == "HEAD"))
        logger.log(addr[0], req, u, len(b))
        
    while True:
        (sock, addr) = q.get()
        msg = sock.recv(4096)
        while msg != b"":
            req = request(msg)
            print(req.method , req.target)
            if req.target != "":
                if os.path.isfile(req.target):
                    if req.target.startswith("cgi-bin"):
                        if req.method == "POST":
                            body = and_split(req.body)
                            f = os.popen(f"python {req.target} {body}", "r")
                            res = f.buffer.readlines()
                            f.close()
                            b = "".encode()
                            for fi in res:
                                b += fi + '\n'.encode()
                            # print(b.decode())
                            sock.send(response(200, MIME.html, b, req.method == "HEAD"))
                            logger.log(addr[0], req, 200, len(b))
                        else:
                            f = os.popen(f"python {req.target}", "r")
                            res = f.buffer.readlines()
                            f.close()
                            b = "".encode()
                            for fi in res:
                                b += fi + '\n'.encode()
                            sock.send(response(200, MIME.html, b, req.method == "HEAD"))
                            logger.log(addr[0], req, 200, len(b))
                    else:
                        send_file(req, req.target, MIME.html)
                else:
                    send_file(req, "404.html", MIME.html)
            else:
                send_file(req, "index.html", MIME.html)
            msg = sock.recv(4096)
        sock.close()


def echo_server(addr):
    active_socket = 0
    tasks = Queue()
    # socket队列，记录max连接的socket
    socket_q = Queue()
    # thread队列，记录max运行的thread
    thread_q = Queue()

    sock = socket(Socket.AF_INET, Socket.SOCK_STREAM)
    sock.settimeout(5000)
    sock.bind(addr)
    sock.listen(5)
    while True:
        
        t = Thread(target=echo_client, args=(tasks, ))
        t.daemon = True
        t.start()
        thread_q.put(t)

        client = sock.accept()
        tasks.put(client)
        socket_q.put(client[0])
        active_socket += 1

        while active_socket > maxConnections:
            th = thread_q.get()
            s  = socket_q.get()
            print(
                'thread = '+str(th),
                '\nsocket = '+str(s),
            )
         
            # 队首线程是否被连带关闭，如果被关闭获取下一个线程
            n = re.search(r"stopped",str(th))
#            while (str(n) != 'None') and active_socket > maxConnections:
#                active_socket -= 1
#                th = thread_q.get()
#                n = re.search(r"stopped",str(th))
#                print(n)
            if str(n) == 'None':
                # 关闭线程
                stop_thread(th)
            print('This thread is stopped!')

            # 关闭socket
            s.close()
            print('This socket is closed!\n')
            active_socket -= 1


if __name__ == "__main__":
    if len(sys.argv) == 1:
        m = 100
    else:
        if len(sys.argv) != 2:
            print("python server.py <maxConnections>")
            exit()
        try:
            m = int(sys.argv[1])
        except ValueError:
            print("python server.py <maxConnections>")
            exit()
    maxConnections = m                                                                                                       
    echo_server(("", 8888))
